package com.example.product.statemachine;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.StateMachinePersist;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class OrderService {

    private Long id = 1L;
    private Map<Long, Order> orders = new ConcurrentHashMap<>();

    @Resource
    private StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine;;
    @Autowired
    private StateMachinePersister<OrderStatusEnum, OrderStatusChangeEventEnum, Order> stateMachinePersister;

    public Order create() {
        Order order = new Order();
        order.setOrderId(id++);
        order.setOrderStatus(OrderStatusEnum.WAIT_PAYMENT);
        orders.put(order.getOrderId(), order);
        System.out.println("order create success:" + order);
        return order;
    }

    public Order pay(Long orderId) {
        Order order = orders.get(orderId);
        System.out.println("try to pay, order no:" + order);
        if (!process(order, OrderStatusChangeEventEnum.PAYED)) {
            System.out.println("pay fail, order no:" + order);
        }
        return orders.get(orderId);
    }

    public Order deliver(Long orderId) {
        Order order = orders.get(orderId);
        System.out.println("try to deliver, order no:" + order);
        if (!process(order, OrderStatusChangeEventEnum.DELIVERY)) {
            System.out.println("deliver fail, order no:" + order);
        }
        return orders.get(orderId);
    }

    public Order receive(Long orderId) {
        Order order = orders.get(orderId);
        System.out.println("try to receive, order no:" + order);
        if (!process(order, OrderStatusChangeEventEnum.RECEIVED)) {
            System.out.println("receive fail, order no:" + order);
        }
        return orders.get(orderId);
    }

    public boolean process(Order order, OrderStatusChangeEventEnum event) {
        Message<OrderStatusChangeEventEnum> message = MessageBuilder.withPayload(event).setHeader("order", order).build();
        return sendEvent(message);
    }

    public synchronized boolean sendEvent(Message<OrderStatusChangeEventEnum> message) {
        boolean result = false;

        try {
            Order order = message.getHeaders().get("order", Order.class);
            stateMachinePersister.restore(orderStateMachine, order);
            result = orderStateMachine.sendEvent(message);
            System.out.println("send order event:" + message);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


}
